#include <test_schwarz.hpp>
#include <iostream>

namespace Life {

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
typename Test_Schwarz<Dim,Order,Entity>::mesh_ptrtype
Test_Schwarz<Dim,Order,Entity>::createMeshTemp( double meshSize )
{

    mesh_ptrtype mesh( new mesh_type );
/*
//    this->changeRepository( boost::format( "MeshGEO/%1%/" )  % this->about().appName() );
    this->changeRepository( boost::format( "MeshGEO/" ) );

    std::ostringstream ostr;
    std::string str;
    std::ifstream fichier("entitie.geo" );
    ostr << "Mesh.MshFileVersion = " << 2 << ";\n";
    ostr << "h = " << meshSize << ";\n";
    while( std::getline( fichier, str ) ) {
        ostr << str << "\n";
    }
*/
double Epcb=1;
double Ea=3;
double Hpcb=6;
double Hic=1;
double Eic=0.5;
double H1=0.5;
double H2=2.5;


    std::ostringstream ostr;
    ostr << "Mesh.MshFileVersion = " << 2 << ";\n"
         << "h=" << meshSize << ";\n"
         << "Epcb=" << Epcb << ";\n"
         << "Ea=" << Ea << ";\n"
         << "Hpcb=" << Hpcb << ";\n"
         << "Hic=" << Hic << ";\n"
         << "Eic=" << Eic << ";\n"
         << "H1=" << H1 << ";\n"
         << "H2=" << H2 << ";\n"
         << "Point(1) = { 0, 0, 0, h};\n"
         << "Point(2) = { Epcb, 0, 0, h};\n"
         << "Point(3) = { Epcb+Ea, 0, 0, h};\n"
         << "Point(4) = { Epcb+Ea, Hpcb, 0, h};\n"
         << "Point(5) = { Epcb, Hpcb, 0, h};\n"
         << "Point(6) = { 0, Hpcb, 0, h};\n"
         << "Point(7) = { Epcb, H1, 0, h};\n"
         << "Point(8) = { Epcb+Eic, H1, 0, h};\n"
         << "Point(9) = { Epcb+Eic, H1+Hic, 0, h};\n"
         << "Point(10) = { Epcb, H1+Hic, 0, h};\n"
         << "Point(11) = { Epcb, H2, 0, h};\n"
         << "Point(12) = { Epcb+Eic, H2, 0, h};\n"
         << "Point(13) = { Epcb+Eic, H2+Hic, 0, h};\n"
         << "Point(14) = { Epcb, H2+Hic, 0, h};\n"
         << "Line(1) = {1, 2};\n"
         << "Line(2) = {2, 3};\n"
         << "Line(3) = {3, 4};\n"
         << "Line(4) = {4, 5};\n"
         << "Line(5) = {5, 6};\n"
         << "Line(6) = {6, 1};\n"
         << "Line(7) = {7, 8};\n"
         << "Line(8) = {8, 9};\n"
         << "Line(9) = {9, 10};\n"
         << "Line(10) = {10, 7};\n"
         << "Line(11) = {11, 12};\n"
         << "Line(12) = {12, 13};\n"
         << "Line(13) = {13, 14};\n"
         << "Line(14) = {14, 11};\n"
         << "Line(15) = {2, 7};\n"
         << "Line(16) = {10, 11};\n"
         << "Line(17) = {14, 5};\n"
         << "Line Loop(18) = {7, 8, 9, 10};\n"
         << "Plane Surface(19) = {18};\n"
         << "Line Loop(20) = {11, 12, 13, 14};\n"
         << "Plane Surface(21) = {20};\n"
         << "Line Loop(22) = {1, 15, -10, 16, -14, 17, 5, 6};\n"
         << "Plane Surface(23) = {22};\n"
         << "Line Loop(24) = {2, 3, 4, -17, -13, -12, -11, -16, -9, -8, -7, -15};\n"
         << "Plane Surface(25) = {24};\n";
/*
         << "Physical Line(\"Bord\") = {1,2,4,5,6};\n"
         << "Physical Line(\"Interface\") = {7};\n"
         << "Physical Line(\"BordDroit\") = {3};\n"
         << "Physical Surface(\"Physique1\") = {2};\n"
         << "Physical Surface(\"Physique2\") = {3};\n";
*/

    this->changeRepository( boost::format( "%1%/%2%/P%3%/h_%4%/" )
                            % this->about().appName()
                            % convex_type::name()
                            % Order
                            % this->vm()["hsize"].template as<double>()
                            );

    Gmsh gmsh;
    std::string fname = gmsh.generate( "domainTemp", ostr.str()  );

    ImporterGmsh<mesh_type> import( fname );
    import.setVersion( "2.0" );
    mesh->accept( import );
//    mesh->setComponents( MESH_UPDATE_EDGES|MESH_UPDATE_FACES );
    mesh->updateForUse();

    return mesh;


} // Test_Schwarz::createMesh

//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//


template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
typename Test_Schwarz<Dim,Order,Entity>::mesh_ptrtype
Test_Schwarz<Dim,Order,Entity>::createMeshFluid( double meshSize )
{

    mesh_ptrtype mesh( new mesh_type );

double Epcb=1;
double Ea=3;
double Hpcb=6;
double Hic=1;
double Eic=0.5;
double H1=0.5;
double H2=2.5;


    std::ostringstream ostr;
    ostr << "Mesh.MshFileVersion = " << 2 << ";\n"
         << "h=" << meshSize << ";\n"
         << "Epcb=" << Epcb << ";\n"
         << "Ea=" << Ea << ";\n"
         << "Hpcb=" << Hpcb << ";\n"
         << "Hic=" << Hic << ";\n"
         << "Eic=" << Eic << ";\n"
         << "H1=" << H1 << ";\n"
         << "H2=" << H2 << ";\n"
//         << "Point(1) = { 0, 0, 0, h};\n"
         << "Point(2) = { Epcb, 0, 0, h};\n"
         << "Point(3) = { Epcb+Ea, 0, 0, h};\n"
         << "Point(4) = { Epcb+Ea, Hpcb, 0, h};\n"
         << "Point(5) = { Epcb, Hpcb, 0, h};\n"
//         << "Point(6) = { 0, Hpcb, 0, h};\n"
         << "Point(7) = { Epcb, H1, 0, h};\n"
         << "Point(8) = { Epcb+Eic, H1, 0, h};\n"
         << "Point(9) = { Epcb+Eic, H1+Hic, 0, h};\n"
         << "Point(10) = { Epcb, H1+Hic, 0, h};\n"
         << "Point(11) = { Epcb, H2, 0, h};\n"
         << "Point(12) = { Epcb+Eic, H2, 0, h};\n"
         << "Point(13) = { Epcb+Eic, H2+Hic, 0, h};\n"
         << "Point(14) = { Epcb, H2+Hic, 0, h};\n"
//         << "Line(1) = {1, 2};\n"
         << "Line(2) = {2, 3};\n"
         << "Line(3) = {3, 4};\n"
         << "Line(4) = {4, 5};\n"
//         << "Line(5) = {5, 6};\n"
//         << "Line(6) = {6, 1};\n"
         << "Line(7) = {7, 8};\n"
         << "Line(8) = {8, 9};\n"
         << "Line(9) = {9, 10};\n"
//         << "Line(10) = {10, 7};\n"
         << "Line(11) = {11, 12};\n"
         << "Line(12) = {12, 13};\n"
         << "Line(13) = {13, 14};\n"
//         << "Line(14) = {14, 11};\n"
         << "Line(15) = {2, 7};\n"
         << "Line(16) = {10, 11};\n"
         << "Line(17) = {14, 5};\n"
//         << "Line Loop(18) = {7, 8, 9, 10};\n"
//         << "Plane Surface(19) = {18};\n"
//         << "Line Loop(20) = {11, 12, 13, 14};\n"
//         << "Plane Surface(21) = {20};\n"
//         << "Line Loop(22) = {1, 15, -10, 16, -14, 17, 5, 6};\n"
//         << "Plane Surface(23) = {22};\n"
         << "Line Loop(24) = {2, 3, 4, -17, -13, -12, -11, -16, -9, -8, -7, -15};\n"
         << "Plane Surface(25) = {24};\n";
/*
         << "Physical Line(\"Bord\") = {1,2,4,5,6};\n"
         << "Physical Line(\"Interface\") = {7};\n"
         << "Physical Line(\"BordDroit\") = {3};\n"
         << "Physical Surface(\"Physique1\") = {2};\n"
         << "Physical Surface(\"Physique2\") = {3};\n";
*/

    this->changeRepository( boost::format( "%1%/%2%/P%3%/h_%4%/" )
                            % this->about().appName()
                            % convex_type::name()
                            % Order
                            % this->vm()["hsize"].template as<double>()
                            );

    Gmsh gmsh;
    std::string fname = gmsh.generate( "domainFluid", ostr.str()  );

    ImporterGmsh<mesh_type> import( fname );
    import.setVersion( "2.0" );
    mesh->accept( import );
//    mesh->setComponents( MESH_UPDATE_EDGES|MESH_UPDATE_FACES );
    mesh->updateForUse();

    return mesh;


} // Test_Schwarz::createMesh

//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
typename Test_Schwarz<Dim,Order,Entity>::mesh_ptrtype
Test_Schwarz<Dim,Order,Entity>::createSubMesh( mesh_ptrtype& mesh, int marker ) 
{
    mesh_ptrtype new_mesh( new mesh_type );

    typedef typename mesh_type::element_const_iterator element_const_iterator;
    typedef typename mesh_type::element_type mesh_element_type;
    
    std::list<mesh_element_type> L1;
    L1.clear();

    //parcours des éléments du maillage
    for ( element_const_iterator elt = mesh->beginElement();  elt != mesh->endElement(); ++elt ) {
      //ajout de l'élément si son marqueur correspond
      if (elt->marker().value()==marker) L1.push_back(*elt);
    }

    typedef typename std::list< mesh_element_type>::iterator list_type;

    //création du sous-maillage
    mesh->template createSubmesh<list_type>( *new_mesh, (L1.begin()) , (L1.end()) );

    return new_mesh;

} // Test_Schwarz::createSubMesh

//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
typename Test_Schwarz<Dim,Order,Entity>::mesh_ptrtype
Test_Schwarz<Dim,Order,Entity>::createMesh1( double meshSize )
{
    mesh_ptrtype mesh( new mesh_type );

    std::ostringstream ostr;
    ostr << "Mesh.MshFileVersion = " << 2 << ";\n"
         << "h=" << meshSize << ";\n"
         << "Point(1) = {-1,-1, 0, h};\n"
         << "Point(2) = { 0,-1, 0, h};\n"
         << "Point(3) = { 0, 1, 0, h};\n"
         << "Point(4) = {-1, 1, 0, h};\n"
         << "Line(1) = {1, 2};\n"
         << "Line(2) = {2, 3};\n"
         << "Line(3) = {3, 4};\n"
         << "Line(4) = {4, 1};\n"
         << "Line Loop(1) = {1, 2, 3 ,4 };\n"
         << "Plane Surface(2) = {1};\n"
         << "Physical Line(\"Bord\") = {1,3,4};\n"
         << "Physical Line(\"Interface\") = {2};\n"
         << "Physical Surface(\"Physique1\") = {2};\n";


    this->changeRepository( boost::format( "%1%/%2%/P%3%/h_%4%/" )
                            % this->about().appName()
                            % convex_type::name()
                            % Order
                            % this->vm()["hsize"].template as<double>()
                            );

    Gmsh gmsh;
    std::string fname = gmsh.generate( "domain1", ostr.str()  );

    ImporterGmsh<mesh_type> import( fname );
    import.setVersion( "2.0" );
    mesh->accept( import );

    return mesh;

}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
typename Test_Schwarz<Dim,Order,Entity>::mesh_ptrtype
Test_Schwarz<Dim,Order,Entity>::createMesh2( double meshSize )
{
    mesh_ptrtype mesh( new mesh_type );

    std::ostringstream ostr;
    ostr << "Mesh.MshFileVersion = " << 2 << ";\n"
         << "h=" << meshSize << ";\n"
         << "Point(1) = { 0,-1, 0, h};\n"
         << "Point(2) = { 1,-1, 0, h};\n"
         << "Point(3) = { 1, 1, 0, h};\n"
         << "Point(4) = { 0, 1, 0, h};\n"
         << "Line(1) = {1, 2};\n"
         << "Line(2) = {2, 3};\n"
         << "Line(3) = {3, 4};\n"
         << "Line(4) = {4, 1};\n"
         << "Line Loop(1) = {1, 2, 3 ,4 };\n"
         << "Plane Surface(2) = {1};\n"
         << "Physical Line(\"Bord\") = {1,2,3};\n"
         << "Physical Line(\"Interface\") = {4};\n"
         << "Physical Surface(\"Physique1\") = {2};\n";


    this->changeRepository( boost::format( "%1%/%2%/P%3%/h_%4%/" )
                            % this->about().appName()
                            % convex_type::name()
                            % Order
                            % this->vm()["hsize"].template as<double>()
                            );

    Gmsh gmsh;
    std::string fname = gmsh.generate( "domain2", ostr.str()  );

    ImporterGmsh<mesh_type> import( fname );
    import.setVersion( "2.0" );
    mesh->accept( import );

    return mesh;

}
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
void
Test_Schwarz<Dim, Order, Entity>::solve( sparse_matrix_ptrtype const& D,
                                   element_type& u,
                                   vector_ptrtype const& F,
                                   bool is_sym )
{
    vector_ptrtype U( M_backend->newVector( u.functionSpace() ) );
    M_backend->solve( D, D, U, F, false );
    u = *U;
} // Test_Schwarz::solve

//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//
//----------------------------------------------------------------------------------------------------------//

template<int Dim, int Order, template<uint16_type,uint16_type,uint16_type> class Entity>
void
Test_Schwarz<Dim, Order, Entity>::exportResults( element_type& U, element_type& U1, element_type& U2, double time  )
{
    exporter->step( time )->setMesh( U.functionSpace()->mesh() );
    exporter->step( time )->add( "u", U );
    exporter->save();
/*
    exporter1->step( time )->setMesh( U1.functionSpace()->mesh() );
    exporter1->step( time )->add( "u1", U1 );
    exporter1->save();

    exporter2->step( time )->setMesh( U2.functionSpace()->mesh() );
    exporter2->step( time )->add( "u2", U2 );
    exporter2->save();*/


} // Test_Schwarz::exportResults



} // Life

// instantiation
template class Life::Test_Schwarz<2,1,Life::Simplex>;
//template class Life::Test_Schwarz<2,2,Life::Simplex>;
//template class Life::Test_Schwarz<3,2,Life::Simplex>;

